home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / gnu / glibc108.gz / glibc108 / glibc-1.08.1 / sunrpc / svc_tcp.c < prev    next >
C/C++ Source or Header  |  1994-02-06  |  10KB  |  420 lines

  1. /* @(#)svc_tcp.c    2.2 88/08/01 4.0 RPCSRC */
  2. /*
  3.  * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
  4.  * unrestricted use provided that this legend is included on all tape
  5.  * media and as a part of the software program in whole or part.  Users
  6.  * may copy or modify Sun RPC without charge, but are not authorized
  7.  * to license or distribute it to anyone else except as part of a product or
  8.  * program developed by the user.
  9.  * 
  10.  * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
  11.  * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
  12.  * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
  13.  * 
  14.  * Sun RPC is provided with no support and without any obligation on the
  15.  * part of Sun Microsystems, Inc. to assist in its use, correction,
  16.  * modification or enhancement.
  17.  * 
  18.  * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
  19.  * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
  20.  * OR ANY PART THEREOF.
  21.  * 
  22.  * In no event will Sun Microsystems, Inc. be liable for any lost revenue
  23.  * or profits or other special, indirect and consequential damages, even if
  24.  * Sun has been advised of the possibility of such damages.
  25.  * 
  26.  * Sun Microsystems, Inc.
  27.  * 2550 Garcia Avenue
  28.  * Mountain View, California  94043
  29.  */
  30. #if !defined(lint) && defined(SCCSIDS)
  31. static char sccsid[] = "@(#)svc_tcp.c 1.21 87/08/11 Copyr 1984 Sun Micro";
  32. #endif
  33.  
  34. /*
  35.  * svc_tcp.c, Server side for TCP/IP based RPC. 
  36.  *
  37.  * Copyright (C) 1984, Sun Microsystems, Inc.
  38.  *
  39.  * Actually implements two flavors of transporter -
  40.  * a tcp rendezvouser (a listner and connection establisher)
  41.  * and a record/tcp stream.
  42.  */
  43.  
  44. #include <stdio.h>
  45. #include <rpc/rpc.h>
  46. #include <sys/socket.h>
  47. #include <errno.h>
  48. extern bool_t abort();
  49. extern errno;
  50.  
  51. /*
  52.  * Ops vector for TCP/IP based rpc service handle
  53.  */
  54. static bool_t        svctcp_recv();
  55. static enum xprt_stat    svctcp_stat();
  56. static bool_t        svctcp_getargs();
  57. static bool_t        svctcp_reply();
  58. static bool_t        svctcp_freeargs();
  59. static void        svctcp_destroy();
  60.  
  61. static struct xp_ops svctcp_op = {
  62.     svctcp_recv,
  63.     svctcp_stat,
  64.     svctcp_getargs,
  65.     svctcp_reply,
  66.     svctcp_freeargs,
  67.     svctcp_destroy
  68. };
  69.  
  70. /*
  71.  * Ops vector for TCP/IP rendezvous handler
  72.  */
  73. static bool_t        rendezvous_request();
  74. static enum xprt_stat    rendezvous_stat();
  75.  
  76. static struct xp_ops svctcp_rendezvous_op = {
  77.     rendezvous_request,
  78.     rendezvous_stat,
  79.     abort,
  80.     abort,
  81.     abort,
  82.     svctcp_destroy
  83. };
  84.  
  85. static int readtcp(), writetcp();
  86. static SVCXPRT *makefd_xprt();
  87.  
  88. struct tcp_rendezvous { /* kept in xprt->xp_p1 */
  89.     u_int sendsize;
  90.     u_int recvsize;
  91. };
  92.  
  93. struct tcp_conn {  /* kept in xprt->xp_p1 */
  94.     enum xprt_stat strm_stat;
  95.     u_long x_id;
  96.     XDR xdrs;
  97.     char verf_body[MAX_AUTH_BYTES];
  98. };
  99.  
  100. /*
  101.  * Usage:
  102.  *    xprt = svctcp_create(sock, send_buf_size, recv_buf_size);
  103.  *
  104.  * Creates, registers, and returns a (rpc) tcp based transporter.
  105.  * Once *xprt is initialized, it is registered as a transporter
  106.  * see (svc.h, xprt_register).  This routine returns
  107.  * a NULL if a problem occurred.
  108.  *
  109.  * If sock<0 then a socket is created, else sock is used.
  110.  * If the socket, sock is not bound to a port then svctcp_create
  111.  * binds it to an arbitrary port.  The routine then starts a tcp
  112.  * listener on the socket's associated port.  In any (successful) case,
  113.  * xprt->xp_sock is the registered socket number and xprt->xp_port is the
  114.  * associated port number.
  115.  *
  116.  * Since tcp streams do buffered io similar to stdio, the caller can specify
  117.  * how big the send and receive buffers are via the second and third parms;
  118.  * 0 => use the system default.
  119.  */
  120. SVCXPRT *
  121. svctcp_create(sock, sendsize, recvsize)
  122.     register int sock;
  123.     u_int sendsize;
  124.     u_int recvsize;
  125. {
  126.     bool_t madesock = FALSE;
  127.     register SVCXPRT *xprt;
  128.     register struct tcp_rendezvous *r;
  129.     struct sockaddr_in addr;
  130.     int len = sizeof(struct sockaddr_in);
  131.  
  132.     if (sock == RPC_ANYSOCK) {
  133.         if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
  134.             perror("svctcp_.c - udp socket creation problem");
  135.             return ((SVCXPRT *)NULL);
  136.         }
  137.         madesock = TRUE;
  138.     }
  139.     bzero((char *)&addr, sizeof (addr));
  140.     addr.sin_family = AF_INET;
  141.     if (bindresvport(sock, &addr)) {
  142.         addr.sin_port = 0;
  143.         (void)bind(sock, (struct sockaddr *)&addr, len);
  144.     }
  145.     if ((getsockname(sock, (struct sockaddr *)&addr, &len) != 0)  ||
  146.         (listen(sock, 2) != 0)) {
  147.         perror("svctcp_.c - cannot getsockname or listen");
  148.         if (madesock)
  149.                (void)close(sock);
  150.         return ((SVCXPRT *)NULL);
  151.     }
  152.     r = (struct tcp_rendezvous *)mem_alloc(sizeof(*r));
  153.     if (r == NULL) {
  154.         (void) fprintf(stderr, "svctcp_create: out of memory\n");
  155.         return (NULL);
  156.     }
  157.     r->sendsize = sendsize;
  158.     r->recvsize = recvsize;
  159.     xprt = (SVCXPRT *)mem_alloc(sizeof(SVCXPRT));
  160.     if (xprt == NULL) {
  161.         (void) fprintf(stderr, "svctcp_create: out of memory\n");
  162.         return (NULL);
  163.     }
  164.     xprt->xp_p2 = NULL;
  165.     xprt->xp_p1 = (caddr_t)r;
  166.     xprt->xp_verf = _null_auth;
  167.     xprt->xp_ops = &svctcp_rendezvous_op;
  168.     xprt->xp_port = ntohs(addr.sin_port);
  169.     xprt->xp_sock = sock;
  170.     xprt_register(xprt);
  171.     return (xprt);
  172. }
  173.  
  174. /*
  175.  * Like svtcp_create(), except the routine takes any *open* UNIX file
  176.  * descriptor as its first input.
  177.  */
  178. SVCXPRT *
  179. svcfd_create(fd, sendsize, recvsize)
  180.     int fd;
  181.     u_int sendsize;
  182.     u_int recvsize;
  183. {
  184.  
  185.     return (makefd_xprt(fd, sendsize, recvsize));
  186. }
  187.  
  188. static SVCXPRT *
  189. makefd_xprt(fd, sendsize, recvsize)
  190.     int fd;
  191.     u_int sendsize;
  192.     u_int recvsize;
  193. {
  194.     register SVCXPRT *xprt;
  195.     register struct tcp_conn *cd;
  196.  
  197.     xprt = (SVCXPRT *)mem_alloc(sizeof(SVCXPRT));
  198.     if (xprt == (SVCXPRT *)NULL) {
  199.         (void) fprintf(stderr, "svc_tcp: makefd_xprt: out of memory\n");
  200.         goto done;
  201.     }
  202.     cd = (struct tcp_conn *)mem_alloc(sizeof(struct tcp_conn));
  203.     if (cd == (struct tcp_conn *)NULL) {
  204.         (void) fprintf(stderr, "svc_tcp: makefd_xprt: out of memory\n");
  205.         mem_free((char *) xprt, sizeof(SVCXPRT));
  206.         xprt = (SVCXPRT *)NULL;
  207.         goto done;
  208.     }
  209.     cd->strm_stat = XPRT_IDLE;
  210.     xdrrec_create(&(cd->xdrs), sendsize, recvsize,
  211.         (caddr_t)xprt, readtcp, writetcp);
  212.     xprt->xp_p2 = NULL;
  213.     xprt->xp_p1 = (caddr_t)cd;
  214.     xprt->xp_verf.oa_base = cd->verf_body;
  215.     xprt->xp_addrlen = 0;
  216.     xprt->xp_ops = &svctcp_op;  /* truely deals with calls */
  217.     xprt->xp_port = 0;  /* this is a connection, not a rendezvouser */
  218.     xprt->xp_sock = fd;
  219.     xprt_register(xprt);
  220.     done:
  221.     return (xprt);
  222. }
  223.  
  224. static bool_t
  225. rendezvous_request(xprt)
  226.     register SVCXPRT *xprt;
  227. {
  228.     int sock;
  229.     struct tcp_rendezvous *r;
  230.     struct sockaddr_in addr;
  231.     int len;
  232.  
  233.     r = (struct tcp_rendezvous *)xprt->xp_p1;
  234.     again:
  235.     len = sizeof(struct sockaddr_in);
  236.     if ((sock = accept(xprt->xp_sock, (struct sockaddr *)&addr,
  237.         &len)) < 0) {
  238.         if (errno == EINTR)
  239.             goto again;
  240.            return (FALSE);
  241.     }
  242.     /*
  243.      * make a new transporter (re-uses xprt)
  244.      */
  245.     xprt = makefd_xprt(sock, r->sendsize, r->recvsize);
  246.     xprt->xp_raddr = addr;
  247.     xprt->xp_addrlen = len;
  248.     return (FALSE); /* there is never an rpc msg to be processed */
  249. }
  250.  
  251. static enum xprt_stat
  252. rendezvous_stat()
  253. {
  254.  
  255.     return (XPRT_IDLE);
  256. }
  257.  
  258. static void
  259. svctcp_destroy(xprt)
  260.     register SVCXPRT *xprt;
  261. {
  262.     register struct tcp_conn *cd = (struct tcp_conn *)xprt->xp_p1;
  263.  
  264.     xprt_unregister(xprt);
  265.     (void)close(xprt->xp_sock);
  266.     if (xprt->xp_port != 0) {
  267.         /* a rendezvouser socket */
  268.         xprt->xp_port = 0;
  269.     } else {
  270.         /* an actual connection socket */
  271.         XDR_DESTROY(&(cd->xdrs));
  272.     }
  273.     mem_free((caddr_t)cd, sizeof(struct tcp_conn));
  274.     mem_free((caddr_t)xprt, sizeof(SVCXPRT));
  275. }
  276.  
  277. /*
  278.  * All read operations timeout after 35 seconds.
  279.  * A timeout is fatal for the connection.
  280.  */
  281. static struct timeval wait_per_try = { 35, 0 };
  282.  
  283. /*
  284.  * reads data from the tcp conection.
  285.  * any error is fatal and the connection is closed.
  286.  * (And a read of zero bytes is a half closed stream => error.)
  287.  */
  288. static int
  289. readtcp(xprt, buf, len)
  290.     register SVCXPRT *xprt;
  291.     caddr_t buf;
  292.     register int len;
  293. {
  294.     register int sock = xprt->xp_sock;
  295. #ifdef FD_SETSIZE
  296.     fd_set mask;
  297.     fd_set readfds;
  298.  
  299.     FD_ZERO(&mask);
  300.     FD_SET(sock, &mask);
  301. #else
  302.     register int mask = 1 << sock;
  303.     int readfds;
  304. #endif /* def FD_SETSIZE */
  305.     do {
  306.         readfds = mask;
  307.         if (select(_rpc_dtablesize(), &readfds, (int*)NULL, (int*)NULL, 
  308.                &wait_per_try) <= 0) {
  309.             if (errno == EINTR) {
  310.                 continue;
  311.             }
  312.             goto fatal_err;
  313.         }
  314. #ifdef FD_SETSIZE
  315.     } while (!FD_ISSET(sock, &readfds));
  316. #else
  317.     } while (readfds != mask);
  318. #endif /* def FD_SETSIZE */
  319.     if ((len = read(sock, buf, len)) > 0) {
  320.         return (len);
  321.     }
  322. fatal_err:
  323.     ((struct tcp_conn *)(xprt->xp_p1))->strm_stat = XPRT_DIED;
  324.     return (-1);
  325. }
  326.  
  327. /*
  328.  * writes data to the tcp connection.
  329.  * Any error is fatal and the connection is closed.
  330.  */
  331. static int
  332. writetcp(xprt, buf, len)
  333.     register SVCXPRT *xprt;
  334.     caddr_t buf;
  335.     int len;
  336. {
  337.     register int i, cnt;
  338.  
  339.     for (cnt = len; cnt > 0; cnt -= i, buf += i) {
  340.         if ((i = write(xprt->xp_sock, buf, cnt)) < 0) {
  341.             ((struct tcp_conn *)(xprt->xp_p1))->strm_stat =
  342.                 XPRT_DIED;
  343.             return (-1);
  344.         }
  345.     }
  346.     return (len);
  347. }
  348.  
  349. static enum xprt_stat
  350. svctcp_stat(xprt)
  351.     SVCXPRT *xprt;
  352. {
  353.     register struct tcp_conn *cd =
  354.         (struct tcp_conn *)(xprt->xp_p1);
  355.  
  356.     if (cd->strm_stat == XPRT_DIED)
  357.         return (XPRT_DIED);
  358.     if (! xdrrec_eof(&(cd->xdrs)))
  359.         return (XPRT_MOREREQS);
  360.     return (XPRT_IDLE);
  361. }
  362.  
  363. static bool_t
  364. svctcp_recv(xprt, msg)
  365.     SVCXPRT *xprt;
  366.     register struct rpc_msg *msg;
  367. {
  368.     register struct tcp_conn *cd =
  369.         (struct tcp_conn *)(xprt->xp_p1);
  370.     register XDR *xdrs = &(cd->xdrs);
  371.  
  372.     xdrs->x_op = XDR_DECODE;
  373.     (void)xdrrec_skiprecord(xdrs);
  374.     if (xdr_callmsg(xdrs, msg)) {
  375.         cd->x_id = msg->rm_xid;
  376.         return (TRUE);
  377.     }
  378.     return (FALSE);
  379. }
  380.  
  381. static bool_t
  382. svctcp_getargs(xprt, xdr_args, args_ptr)
  383.     SVCXPRT *xprt;
  384.     xdrproc_t xdr_args;
  385.     caddr_t args_ptr;
  386. {
  387.  
  388.     return ((*xdr_args)(&(((struct tcp_conn *)(xprt->xp_p1))->xdrs), args_ptr));
  389. }
  390.  
  391. static bool_t
  392. svctcp_freeargs(xprt, xdr_args, args_ptr)
  393.     SVCXPRT *xprt;
  394.     xdrproc_t xdr_args;
  395.     caddr_t args_ptr;
  396. {
  397.     register XDR *xdrs =
  398.         &(((struct tcp_conn *)(xprt->xp_p1))->xdrs);
  399.  
  400.     xdrs->x_op = XDR_FREE;
  401.     return ((*xdr_args)(xdrs, args_ptr));
  402. }
  403.  
  404. static bool_t
  405. svctcp_reply(xprt, msg)
  406.     SVCXPRT *xprt;
  407.     register struct rpc_msg *msg;
  408. {
  409.     register struct tcp_conn *cd =
  410.         (struct tcp_conn *)(xprt->xp_p1);
  411.     register XDR *xdrs = &(cd->xdrs);
  412.     register bool_t stat;
  413.  
  414.     xdrs->x_op = XDR_ENCODE;
  415.     msg->rm_xid = cd->x_id;
  416.     stat = xdr_replymsg(xdrs, msg);
  417.     (void)xdrrec_endofrecord(xdrs, TRUE);
  418.     return (stat);
  419. }
  420.